﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace Mrkz.ImageManipulation.FrequencyFiltering
{
    internal static class DFTEngineSupportFunctions
    {
        public static TImage<ComplexPixel> ParallelDFT2D(TImage<ComplexPixel> InputData, int Direction)
        {
            int Height = (InputData.Height);
            int Width = (InputData.Width);

            Complex[,] out_R = new Complex[Height, Width];
            Complex[,] out_G = new Complex[Height, Width];
            Complex[,] out_B = new Complex[Height, Width];

            //per ogni colonna            
            Parallel.For(0, Width, (x) =>
            {
                Complex[] _R = new Complex[Height];
                Complex[] _G = new Complex[Height];
                Complex[] _B = new Complex[Height];

                //copio tutta la colonna
                for (int y = 0; y < Height; y++)
                {
                    ComplexPixel p = InputData.GetPixelWithPad(y, x);

                    _R[y] = p.CRed;
                    _G[y] = p.CGreen;
                    _B[y] = p.CBlue;
                }

                _R = NormalizedDFT1D(_R, Direction);
                _G = NormalizedDFT1D(_G, Direction);
                _B = NormalizedDFT1D(_B, Direction);

                //copio la colonna nell'array output
                for (int y = 0; y < Height; y++)
                {
                    out_R[y, x] = _R[y];
                    out_G[y, x] = _G[y];
                    out_B[y, x] = _B[y];
                }
            });


            //per ogni riga
            Parallel.For(0, Height, (y) =>
            {
                Complex[] _R = new Complex[Width];
                Complex[] _G = new Complex[Width];
                Complex[] _B = new Complex[Width];

                //copio tutta la riga
                for (int x = 0; x < Width; x++)
                {
                    _R[x] = out_R[y, x];
                    _G[x] = out_G[y, x];
                    _B[x] = out_B[y, x];
                }

                _R = NormalizedDFT1D(_R, Direction);
                _G = NormalizedDFT1D(_G, Direction);
                _B = NormalizedDFT1D(_B, Direction);

                //copio la riga nell'array output
                for (int x = 0; x < Width; x++)
                {
                    out_R[y, x] = _R[x];
                    out_G[y, x] = _G[x];
                    out_B[y, x] = _B[x];
                }
            });

            return ImageFactory<ComplexPixel>.FromComplexPixelArray(Height, Width, InputData.CropArea, out_R, out_G, out_B);

        }
        /// <summary>
        /// Implementazione della DFT su array di numeri complessi
        /// </summary>
        /// <param name="InputArray">input data</param>
        /// <param name="Direction">+1 forward, -1 reverse</param>
        /// <returns>result array</returns>
        public static Complex[] NormalizedDFT1D(Complex[] inputarray, int dir)
        {
            int N = inputarray.Length;
            Complex[] outputarray = new Complex[N];

            for (int k = 0; k < N; k++)
            {
                for (int n = 0; n < N; n++)
                {
                    outputarray[k] += inputarray[n] *
                                Complex.FromPolarCoordinates(1, (dir * -2) * (Math.PI * n * k) / N);
                }

                outputarray[k] /= Math.Sqrt(N);
            }
            return outputarray;
        }

    }
}
